/* CountryLookup.cs
 *
 * Copyright (C) 2008 MaxMind, Inc.  All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Net;


namespace CountryLookup
{
	/// <summary>
	/// Summary description for CountryLookup.
	/// </summary>
	public class Lookup
	{
		private FileStream fileInput;
		private static long COUNTRY_BEGIN = 16776960;
		
		public Lookup(string fileName)
		{
			try
			{
				fileInput = new FileStream(fileName, FileMode.Open, FileAccess.Read);
			}
			catch (FileNotFoundException e)
			{
				Console.WriteLine("File " + fileName + " not found.");
			}
		}

		private long addrToNum(IPAddress addr) 
		{
			long ipnum = 0;
			byte[] b = addr.GetAddressBytes();
			for (int i = 0; i < 4; ++i) 
			{
				long y = b[i];
				if (y < 0) 
				{
					y+= 256;
				}
				ipnum += y << ((3-i)*8);
			}
			//Console.WriteLine(ipnum);
			return ipnum;
		}

	    public Country LookupCountry(IPAddress addr)
	    {
	        return Country.Countries[(int) SeekCountry(0, addrToNum(addr), 31)];
	    }

		private long SeekCountry(long offset, long ipnum, int depth) 
		{
			byte [] buf = new byte[6];
			long [] x = new long[2];
			if (depth < 0) 
			{
				Console.WriteLine("Error seeking country.");
				return 0; // N/A
			}
			try 
			{
				fileInput.Seek(6 * offset, 0);
				fileInput.Read(buf, 0, 6);
			}
			catch (IOException e) 
			{
				Console.WriteLine("IO Exception");
			}
			for (int i = 0; i<2; i++) 
			{
				x[i] = 0;
				for (int j = 0; j<3; j++) 
				{
					int y = buf[i*3+j];
					if (y < 0) 
					{
						y+= 256;
					}
					x[i] += (y << (j * 8));
				}
			}

			if ((ipnum & (1 << depth)) > 0) 
			{
				if (x[1] >= COUNTRY_BEGIN) 
				{
					return x[1] - COUNTRY_BEGIN;
				}
				return SeekCountry(x[1], ipnum, depth-1);
			} 
			else 
			{
				if (x[0] >= COUNTRY_BEGIN) 
				{
					return x[0] - COUNTRY_BEGIN;
				}
				return SeekCountry(x[0], ipnum, depth-1);
			}
		}
	}
}
